﻿using System;
using System.Collections.Generic;
using System.Configuration;
using System.IO;
using System.Linq;
using System.Net;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Web;
using beway.common;
using System.Xml;
using Beway.ValueAdded.Util;
using Beway.ValueAdded.Model.WeiXinModel;

namespace Beway.ValueAdded.Service
{
    public class WeiXinRedpackSvc
    { 
        /// <summary>
        /// 发送微信红包
        /// </summary>
        /// <param name="payForWeiXin">微信openId</param>
        /// <param name="err">失败时的错误信息</param>
        /// <returns>发送是否成功</returns>
        public bool SendWeiXinRedpack(PayWeiXin payForWeiXin, out string err)
        {
            bool isSend = false;
            err = "";

            string postData = RedpackXmlData(payForWeiXin);
            var result = SendRedpack(postData, payForWeiXin.CertPath, payForWeiXin.CertPwd);
            if (result.return_code.Equals("SUCCESS") && result.result_code.Equals("SUCCESS"))
            {
                isSend = true;
            }
            else
            {
                if (result.result_code.Equals("FAIL"))
                {
                    //这两种状态下，暂定为发送成功(根据微信红包文档，这两种情况不能确认为发送失败，所以默认为成功，后期需要手动去查询（自动未开发）发送状态） by lmh 2019-06-08
                    if(result.err_code.Equals("SYSTEMERROR")|| result.err_code.Equals("PROCESSING"))
                    {
                        isSend = true;
                        err = "发送中(结果以微信支付平台为准)" + result.err_code + " " + result.err_code_des;
                        return isSend;
                    }
                }             

                err = "红包发送失败，原因：" + result.err_code + " " + result.err_code_des;
            }
            return isSend;
        }


        /// <summary>
        /// 调用微信支付接口前处理数据，包括sign验证等
        /// </summary>
        /// <param name="payForWeiXin"></param>
        /// <returns></returns>
        private string RedpackXmlData(PayWeiXin payForWeiXin)
        {
            string postData = @"<xml> 
                                 <mch_billno>{0}</mch_billno> 
                                 <mch_id>{1}</mch_id> 
                                 <wxappid>{2}</wxappid>                                  
                                 <send_name>{3}</send_name> 
                                 <re_openid>{4}</re_openid> 
                                 <total_amount>{5}</total_amount>                                  
                                 <total_num>{6}</total_num> 
                                 <wishing>{7}</wishing> 
                                 <client_ip>{8}</client_ip> 
                                 <act_name>{9}</act_name>                                 
                                 <remark>{10}</remark>
                                 <scene_id><![CDATA[{11}]]></scene_id>
                                 <nonce_str>{12}</nonce_str>";
            postData = string.Format(postData,
                                            payForWeiXin.mch_billno,
                                            payForWeiXin.mch_id,
                                            payForWeiXin.wxappid,
                                            payForWeiXin.send_name,
                                            payForWeiXin.re_openid,
                                            payForWeiXin.total_amount,
                                            payForWeiXin.total_num,
                                            payForWeiXin.wishing,
                                            payForWeiXin.client_ip,
                                            payForWeiXin.act_name,
                                            payForWeiXin.remark,
                                            payForWeiXin.scene_id,
                                            payForWeiXin.nonce_str
                                );


            //原始传入参数
            string[] signTemp = { "mch_billno=" + payForWeiXin.mch_billno, "mch_id=" + payForWeiXin.mch_id, "wxappid=" + payForWeiXin.wxappid, "send_name=" + payForWeiXin.send_name, "re_openid=" + payForWeiXin.re_openid, "total_amount=" + payForWeiXin.total_amount, "total_num=" + payForWeiXin.total_num, "wishing=" + payForWeiXin.wishing, "client_ip=" + payForWeiXin.client_ip, "act_name=" + payForWeiXin.act_name, "remark=" + payForWeiXin.remark, "scene_id=" + payForWeiXin.scene_id, "nonce_str=" + payForWeiXin.nonce_str };

            List<string> signList = signTemp.ToList();


            #region 处理支付签名
            //对signList按照ASCII码从小到大的顺序排序
            signList.Sort();

            string signOld = signList.Aggregate(string.Empty, (current, temp) => current + (temp + "&"));

            //拼接Key
            signOld += "key=" + payForWeiXin.key;
            //处理支付签名
            payForWeiXin.sign = beway.common.Encryption.Md5Encry32bit(signOld).ToUpper();
            #endregion
            postData += "<sign>{0}</sign></xml>";
            postData = string.Format(postData, payForWeiXin.sign);
            return postData;        
        }
        
        /// <summary>
        /// 调用微信发红包接口
        /// </summary>
        /// <param name="postData">提交数据 RedpackXmlData方法返回的数据</param>
        /// <param name="certPath">证书路径</param>
        /// <param name="password">证书密码</param>
        /// <returns>返回调用结果xml数据的实体对象</returns>
        private ReturnResult SendRedpack(string postData, string certPath, string password)
        {
            ReturnResult result = null;
            try
            {
                result = PostPage("https://api.mch.weixin.qq.com/mmpaymkttransfers/sendredpack", postData,certPath,password);
                //LogManager.Write("开始发送红包。。。");
            }
            catch (Exception ex)
            {
                //LogManager.Write(string.Format("发送红包出错，错误信息：{0}", ex.InnerException.ToString()));
            }
            return result;
        }


        /// <summary>
        /// post微信请求
        /// </summary>
        /// <param name="posturl"></param>
        /// <param name="postData"></param>
        /// <param name="certPath"></param>
        /// <param name="password"></param>
        /// <returns></returns>
        private ReturnResult PostPage(string posturl, string postData, string certPath, string password)
        {
            ReturnResult ret_result =  new ReturnResult ();
            Stream outstream = null;
            Stream instream = null;
            StreamReader sr = null;
            HttpWebResponse response = null;
            HttpWebRequest request = null;
            Encoding encoding = Encoding.UTF8;
            byte[] data = encoding.GetBytes(postData);
            // 准备请求...  
            try
            {
                X509Certificate2 cert = new System.Security.Cryptography.X509Certificates.X509Certificate2(certPath, password, X509KeyStorageFlags.MachineKeySet);

                // 设置参数  
                request = WebRequest.Create(posturl) as HttpWebRequest;
                CookieContainer cookieContainer = new CookieContainer();
                request.CookieContainer = cookieContainer;
                request.AllowAutoRedirect = true;
                request.Method = "POST";
                request.ContentType = "text/xml";
                request.ContentLength = data.Length;
                request.ClientCertificates.Add(cert);
                outstream = request.GetRequestStream();
                outstream.Write(data, 0, data.Length);
                outstream.Close();
                //发送请求并获取相应回应数据  
                response = request.GetResponse() as HttpWebResponse;
                //直到request.GetResponse()程序才开始向目标网页发送Post请求  
                instream = response.GetResponseStream();
                sr = new StreamReader(instream, encoding);
                //返回结果网页（html）代码  
                string content = sr.ReadToEnd();
                if (!string.IsNullOrWhiteSpace(content))
                {
                    XmlDocument doc = new XmlDocument();
                    doc.LoadXml(content);
                    
                    //此字段是通信标识，非交易标识
                    ret_result.return_code = doc.GetElementsByTagName("return_code")[0].InnerText;
                    //返回信息，如非空，为错误原因
                    ret_result.return_msg = doc.GetElementsByTagName("return_msg")[0].InnerText;
                    if (ret_result.return_code == "SUCCESS")
                    {

                        ret_result.result_code = doc.GetElementsByTagName("result_code")[0].InnerText;
                        if (ret_result.result_code == "SUCCESS")
                        {
                            //订单号
                            ret_result.mch_billno = doc.GetElementsByTagName("mch_billno")[0].InnerText;

                            //商户appid
                            ret_result.wxappid = doc.GetElementsByTagName("wxappid")[0].InnerText;

                            //接受收红包的用户
                            ret_result.re_openid = doc.GetElementsByTagName("re_openid")[0].InnerText;

                            //付款金额，单位分
                            ret_result.total_amount = doc.GetElementsByTagName("total_amount")[0].InnerText;

                            //发放成功时间
                            ret_result.send_time = doc.GetElementsByTagName("send_time")[0].InnerText;

                            //微信单号
                            ret_result.send_listid = doc.GetElementsByTagName("send_listid")[0].InnerText;
                        }
                        else
                        {
                            ret_result.err_code = doc.GetElementsByTagName("err_code")[0].InnerText;
                            ret_result.err_code_des = doc.GetElementsByTagName("err_code_des")[0].InnerText;
                        }
                    }
                    else
                    {
                        ret_result.err_code = doc.GetElementsByTagName("err_code")[0].InnerText;
                        ret_result.err_code_des = doc.GetElementsByTagName("err_code_des")[0].InnerText;
                    }
                }
            }
            catch (Exception ex)
            {
                ret_result.err_code_des = ex.Message;
                
            }

            return ret_result;
        } 
    }
}
